package com.anecdote.ideaplugins.changesbar;

/**
 * Copyright 2006 Nathan Brown
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.components.ApplicationComponent;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.util.*;
import org.jdom.Element;
import org.jetbrains.annotations.*;

import javax.swing.*;
import javax.swing.event.*;

public class ChangesBarApplicationComponent implements ApplicationComponent, JDOMExternalizable, Configurable
{
  private static boolean _watchForCollisions = true;
  private static boolean _showPopup = true;
  //  public static boolean _markOtherChangelistFilesReadOnly;
  private static boolean _addCommentEditor = true;
  private static boolean _addChangelistScope = false;
  private static boolean _expandChangelistScope = true;
  private static boolean _closeFilesWhenSwitchingChangelist = false;
  private static boolean _openFilesWhenSwitchingChangelist = false;
  private static boolean _openFilesInBackground = true;
  private static final Icon CONFIG_ICON = IconLoader.getIcon("/com/anecdote/ideaplugins/changesbar/configicon.png");
  private static final String WATCH_FOR_COLLISIONS = "watchForCollisions";
  //  private static final String MARK_OTHER_CHANGELIST_FILES_READ_ONLY = "markOtherChangelistFilesReadOnly";
  private static final String ADD_COMMENT_EDITOR = "addCommentEditor";
  private static final String ADD_CHANGELIST_SCOPE = "addChangelistScope";
  private static final String EXPAND_CHANGELIST_SCOPE = "expandChangelistScope";
  private static final String CLOSE_FILES_WHEN_SWITCHING_CHANGELIST = "closeFilesWhenSwitchingChangelist";
  private static final String OPEN_FILES_WHEN_SWITCHING_CHANGELIST = "openFilesWhenSwitchingChangelist";
  private static final String OPEN_FILES_IN_BACKGROUND = "openFilesInBackground";
  private static final String SHOW_POPUP = "showPopup";
  private ChangesBarConfigurationForm _form;
  private static final DefaultActionGroup CHANGES_BAR_COMMIT_COMMENT_ACTION_GROUP = new DefaultActionGroup();

  public ChangesBarApplicationComponent()
  {
  }

  public void initComponent()
  {
    ActionManager.getInstance().registerAction(ChangesBarProjectComponent.CHANGES_BAR_COMMIT_COMMENT_ACTIONS,
                                               CHANGES_BAR_COMMIT_COMMENT_ACTION_GROUP);
  }

  public void disposeComponent()
  {
  }

  @NotNull
  public String getComponentName()
  {
    return "ChangesBarApplicationComponent";
  }

  public void readExternal(Element element) throws InvalidDataException
  {
    _watchForCollisions = readBoolean(element, WATCH_FOR_COLLISIONS, true);
    _showPopup = readBoolean(element, SHOW_POPUP, true);
    _addCommentEditor = readBoolean(element, ADD_COMMENT_EDITOR, true);
    _addChangelistScope = readBoolean(element, ADD_CHANGELIST_SCOPE, false);
    _expandChangelistScope = readBoolean(element, EXPAND_CHANGELIST_SCOPE, true);
    _closeFilesWhenSwitchingChangelist = readBoolean(element, CLOSE_FILES_WHEN_SWITCHING_CHANGELIST, false);
    _openFilesWhenSwitchingChangelist = readBoolean(element, OPEN_FILES_WHEN_SWITCHING_CHANGELIST, false);
    _openFilesInBackground = readBoolean(element, OPEN_FILES_IN_BACKGROUND, true);
  }

  private static Boolean readBoolean(Element element, String elementName, Boolean defaultValue)
  {
    final Element child = element.getChild(elementName);
    if (child != null) {
      defaultValue = Boolean.valueOf(child.getTextTrim());
    }
    return defaultValue;
  }

  public void writeExternal(Element element) throws WriteExternalException
  {
    writeBoolean(element, WATCH_FOR_COLLISIONS, _watchForCollisions);
    writeBoolean(element, SHOW_POPUP, _showPopup);
    writeBoolean(element, ADD_COMMENT_EDITOR, _addCommentEditor);
    writeBoolean(element, ADD_CHANGELIST_SCOPE, _addChangelistScope);
    writeBoolean(element, EXPAND_CHANGELIST_SCOPE, _expandChangelistScope);
    writeBoolean(element, CLOSE_FILES_WHEN_SWITCHING_CHANGELIST, _closeFilesWhenSwitchingChangelist);
    writeBoolean(element, OPEN_FILES_WHEN_SWITCHING_CHANGELIST, _openFilesWhenSwitchingChangelist);
    writeBoolean(element, OPEN_FILES_IN_BACKGROUND, _openFilesInBackground);
  }

  private static void writeBoolean(Element element, String elementName, boolean value)
  {
    final Element childElement = new Element(elementName);
    childElement.setText(String.valueOf(value));
    element.addContent(childElement);
  }

  private static final EventListenerList _listenerList = new EventListenerList();

  /**
   * Adds a listener that's notified each time a Change is fired.
   *
   * @param l the <code>ChangeListener</code> to be added
   */
  static void addChangeListener(ChangeListener l)
  {
    _listenerList.add(ChangeListener.class, l);
  }

  /**
   * Removes a listener that's notified each time a Change is fired.
   *
   * @param l the <code>ListDataListener</code> to be removed
   */
  static void removeChangeListener(ChangeListener l)
  {
    _listenerList.remove(ChangeListener.class, l);
  }

  /**
   * Fires a Changed event.
   */
  private static void fireChanged()
  {
    final ChangeEvent event = new ChangeEvent(ChangesBarApplicationComponent.class);
    final Object[] listeners = _listenerList.getListenerList();
    for (int i = listeners.length - 2; i >= 0; i -= 2) {
      if (listeners[i] == ChangeListener.class) {
        ((ChangeListener)listeners[i + 1]).stateChanged(event);
      }
    }
  }

//  public static boolean isMarkOtherChangelistFilesReadOnly()
//  {
//    return _markOtherChangelistFilesReadOnly;
//  }
//
//  public static void setMarkOtherChangelistFilesReadOnly(final boolean markOtherChangelistFilesReadOnly)
//  {
//    if (markOtherChangelistFilesReadOnly != _markOtherChangelistFilesReadOnly) {
//      _markOtherChangelistFilesReadOnly = markOtherChangelistFilesReadOnly;
//      fireChanged();
//    }
//  }

  //

  static boolean isAddCommentEditor()
  {
    return _addCommentEditor;
  }

  static void setAddCommentEditor(boolean addCommentEditor)
  {
    if (_addCommentEditor != addCommentEditor) {
      _addCommentEditor = addCommentEditor;
      fireChanged();
    }
  }

  static boolean isShowPopup()
  {
    return _showPopup;
  }

  static void setShowPopup(boolean showPopup)
  {
    if (_showPopup != showPopup) {
      _showPopup = showPopup;
      fireChanged();
    }
  }

  static boolean isWatchForCollisions()
  {
    return _watchForCollisions;
  }

  static void setWatchForCollisions(boolean watchForCollisions)
  {
    if (_watchForCollisions != watchForCollisions) {
      _watchForCollisions = watchForCollisions;
      fireChanged();
    }
  }

  static boolean isAddChangelistScope()
  {
    return _addChangelistScope;
  }

  static void setAddChangelistScope(boolean addChangesScope)
  {
    if (_addChangelistScope != addChangesScope) {
      _addChangelistScope = addChangesScope;
      fireChanged();
    }
  }

  static boolean isExpandChangelistScope()
  {
    return _expandChangelistScope;
  }

  static void setExpandChangelistScope(boolean expandChangesScope)
  {
    if (_expandChangelistScope != expandChangesScope) {
      _expandChangelistScope = expandChangesScope;
      fireChanged();
    }
  }

  public static boolean isCloseFilesWhenSwitchingChangelist()
  {
    return _closeFilesWhenSwitchingChangelist;
  }

  public static void setCloseFilesWhenSwitchingChangelist(boolean closeFilesWhenSwitchingChangelist)
  {
    if (_closeFilesWhenSwitchingChangelist != closeFilesWhenSwitchingChangelist) {
      _closeFilesWhenSwitchingChangelist = closeFilesWhenSwitchingChangelist;
      fireChanged();
    }
  }


  public static boolean isOpenFilesWhenSwitchingChangelist()
  {
    return _openFilesWhenSwitchingChangelist;
  }

  public static void setOpenFilesWhenSwitchingChangelist(boolean openFilesWhenSwitchingChangelist)
  {
    if (_openFilesWhenSwitchingChangelist != openFilesWhenSwitchingChangelist) {
      _openFilesWhenSwitchingChangelist = openFilesWhenSwitchingChangelist;
      fireChanged();
    }
  }

  public static boolean isOpenFilesInBackground()
  {
    return _openFilesInBackground;
  }

  public static void setOpenFilesInBackground(boolean openFilesInBackground)
  {
    if (_openFilesInBackground != openFilesInBackground) {
      _openFilesInBackground = openFilesInBackground;
      fireChanged();
    }
  }

  @Nls
  public String getDisplayName()
  {
    return "Changes Bar";
  }

  @Nullable
  public Icon getIcon()
  {
    return CONFIG_ICON;
  }

  @Nullable
  @NonNls
  public String getHelpTopic()
  {
    return null;
  }

  public JComponent createComponent()
  {
    if (_form == null) {
      _form = new ChangesBarConfigurationForm();
    }
    return _form.getRootComponent();
  }

  public boolean isModified()
  {
    return _form != null && _form.isModified(this);
  }

  public void apply() throws ConfigurationException
  {
    if (_form != null) {
      _form.getData(this);
    }
  }

  public void reset()
  {
    if (_form != null) {
      _form.setData(this);
    }
  }

  public void disposeUIResources()
  {
    _form = null;
  }
}
